Логические выражения
====================

.. index::
  writeln

Фактическая работа, выполняемая программой, выполняется с помощью выражений. Любая часть
программы, которая создает значение или побочный эффект, называется выражением. У него
очень широкое определение, потому что даже постоянное значение, такое как 42, и строка, такая как
"hello", являются выражениями, поскольку они создают соответствующие постоянные значения 42 и "hello".

Примечание: Не путайте создание значения с определением переменной. Значения не обязательно должны быть
связаны с переменными.

Вызовы функций, таких как writeln, также являются выражениями, поскольку у них есть побочные эффекты.
эффекты. В случае writeln эффект оказывается на выходной поток путем размещения
в нем символов. Другим примером из программ, которые мы написали до сих
пор, была бы операция присваивания, которая влияет на переменную, находящуюся в левой части.
Поскольку выражения генерируют значения, они могут участвовать в других выражениях.
Это позволяет нам формировать более сложные выражения из более простых.
Например, предполагая, что существует функция с именем currentTemperature, которая
выдает значение текущей температуры воздуха, значение, которое она выдает, может
непосредственно использоваться в выражении writeln:

.. code-block:: d

    writeln("Это ", currentTemperature(), "температура на данный момент".);


Эта строка состоит из четырех выражений:

#. "Это"
#. currentTemperature()
#. "температура на данный момент".
#. Выражение writeln(), использующее три других

В этой главе мы рассмотрим конкретный тип выражения, который используется в условных операторах.
Однако, прежде чем идти дальше, я хотел бы повторить оператор присваивания еще раз,
на этот раз подчеркнув два выражения, которые появляются слева от него и
правые части: оператор присваивания (=) присваивает значение выражения в
правой части выражению в левой части (например, переменной).

.. code-block:: c++

    currentTemperature = 23 // значение температуры становится равным 23


Логические выражения
---------------------


.. index::
  логические выражения

Логические выражения - это выражения, которые используются в математической логике.
Логические выражения - это то, что заставляет компьютерные программы принимать решения типа "если
ответ положительный, я сохраню файл".
Логические выражения могут иметь одно из двух значений:

#.  false, указывающее на ложность
#.  true, указывающее на истинность


В следующих примерах я буду использовать выражения writeln. Если
в конце строки напечатано значение true, это будет означать, что то, что напечатано в строке, является истинным. Аналогично,
значение false будет означать, что то, что находится в строке, является ложным. Например, если вывод программы следующий,

.. code-block:: console

    Есть кофе: true , то это будет означать, что "есть кофе". Аналогично,
    Есть кофе: значение false будет означать, что "кофе нет".

Я использую конструкцию "... is...: false" для обозначения "не является" или "является ложным".
Логические выражения широко используются в условных операторах, циклах, функциях
параметры и т.д. Важно понимать, как они работают. К счастью, логические
выражения легко объяснить и использовать.
Логические операторы, которые используются в логических выражениях, следующие:
Оператор == отвечает на вопрос "равно?" Он сравнивает
выражение в левой части с выражением в правой части и выдает значение true, если они
равны, и значение false, если они не равны. По определению, значение, которое выдает ==, является логическим выражением.
В качестве примера давайте предположим, что у нас есть следующие две переменные:

.. code-block:: d

    daysInWeek = 7;
    monthsInYear = 12;


Ниже приведены два логических выражения, которые используют эти значения:

.. code-block:: d

    daysInWeek == 7 // true
    monthsInYear == 11 // false

Оператор != отвечает на вопрос "не равно?" Он сравнивает два
выражения на своих сторонах и выдает значение, противоположное.

.. code-block:: d

    daysInWeek != 7 // ложь
    monthsInYear != 11 // истина

Оператор ||
-----------

.. index::
  ||

Оператор || означает "или" и выдает значение true, если любое из логических выражений истинно.
Если значение левого выражения равно true, оно выдает значение true,
даже не глядя на выражение, которое находится в правой части. Если левое выражение имеет значение true.
side равно false, тогда он выдает значение правой части. Этот оператор
аналогичен "or" в английском языке: если левый, правый или оба они равны true, тогда он выдает true.


В следующей таблице представлены все возможные значения для обеих сторон этого

.. list-table:: Таблица истинности для операции ||
   :widths: 25 25 25 50
   :header-rows: 1
   :align: center

   * - левая часть
     - оператор
     - правая часть
     - результат
   * - false
     - ||
     - false
     - false
   * - false
     - ||
     - true
     - true
   * - true
     - ||
     - false (не вычисляется)
     - true
   * - true
     - ||
     - true (не вычисляется)
     - true


.. code-block:: d

    import std.stdio;

    void main()
    {
        // false означает "нет", true означает "да"
        bool existsCoffee = false;
        bool existsTea = true;
        writeln("Есть теплый напиток: ", existsCoffee || existsTea);
    }


Поскольку по крайней мере одно из двух выражений истинно,
приведенное выше логическое выражение выдает значение true.

Опрератор &&
-------------

.. index::
  &&

Оператор && означает "и" и выдает значение true, если оба выражения истинны.
Если значение левого выражения равно false, оно выдает значение false,даже не глядя на выражение, которое находится в правой части.
Если левая часть равна true, то она выдает значение правой части. Этот оператор
аналогичен "and" в английском языке: если левое значение и правое значение равны true,тогда это выдает значение true.

.. list-table:: Таблица истинности для операции &&
   :widths: 25 25 25 50
   :header-rows: 1
   :align: center

   * - левая часть
     - оператор
     - правая часть
     - результат
   * - false
     - ||
     - false (не вычисляется)
     - false
   * - false
     - ||
     - true (не вычисляется)
     - false
   * - true
     - ||
     - false
     - false
   * - true
     - ||
     - true
     - true


.. code-block:: d

    writeln("Я буду пить кофе: ", wantToDrinkCoffee && existsCoffee);


Примечание: Тот факт, что операторы || и && могут не вычислять правостороннее
выражение, называется их ленивым поведением. Троичный оператор ?:, который
мы увидим в следующей главе, похож тем, что он никогда не вычисляет одно из своих трех
выражений. Все остальные операторы всегда вычисляют и используют все свои
выражения.

Оператор ^ (исключающие или)
----------------------------

.. index::
  ^

Оператор ^ отвечает на вопрос "является ли одно или другое, но не оба?". Этот
оператор выдает значение true, если истинно только одно выражение, но не оба.
Предупреждение: На самом деле этот оператор является не логическим, а арифметическим
Он ведет себя как логический оператор, только если оба выражения являются bool.

.. list-table:: Таблица истинности для операции ^
   :widths: 25 25 25 50
   :header-rows: 1
   :align: center

   * - левая часть
     - оператор
     - правая часть
     - результат
   * - false
     - ^
     - false
     - false
   * - false
     - ^
     - true
     - true
   * - true
     - ^
     - false
     - true
   * - true
     - ^
     - true
     - false


Например, логика, которая представляет мою игру в шахматы, если появляется только один из двух моих
друзей, может быть закодирована следующим образом:

.. code-block:: d

    writeln("Я буду играть в шахматы: ", jimShowedUp ^ bobShowedUp);

Оператор <
-----------

Оператор < отвечает на вопрос "меньше, чем?" (или "предшествует впорядке сортировки?").

.. code-block:: d

    writeln("Мы победили: ", theirResult < ourResult);

Оператор >
----------

.. index::
  \>

Оператор > отвечает на вопрос "больше, чем?" (или "следует ли после в порядке сортировки?").

.. code-block:: d

    writeln("Они победили: ", theirResult > ourResult);

Оператор <=
-----------

.. index::
   <=

Оператор <= отвечает на вопрос "меньше или равно?" (или "предшествует или совпадает в порядке сортировки?").
Этот оператор противоположен оператору >

.. code-block:: d

    writeln("Нас не победили: ", theirResult <= ourResult);

Оператор >=
-----------
.. index::
  \>=

Оператор >= отвечает на вопрос "больше или равно?" (или "
следует после или совпадает в порядке сортировки?"). Этот оператор противоположен оператору <

.. code-block:: d

    writeln("Мы не победили: ", theirResult >= ourResult);


Оператор !
----------
.. index::
  !

Оператор ! означает "отрицание". В отличие от других логических
операторов, он принимает только одно выражение и выдает значение

* true, если это выражение равно false,
* false если это выражение true.

.. code-block:: d

    writeln("Я пройду: ", !existsBicycle);


Группировка выражений
----------------------

.. index::
  группировка выражений

Порядок, в котором вычисляются выражения, может быть задан с помощью
круглые скобки, чтобы сгруппировать их. Когда выражения, заключенные в круглые скобки, отображаются в более
сложных выражениях, выражения, заключенные в круглые скобки, вычисляются, прежде чем их
можно будет использовать в выражениях, в которых они отображаются. Например, выражение "если
есть кофе или чай, а также печенье или булочка, то я счастлив" может быть закодировано следующим
образом:

.. code-block:: d

    writeln("Я счастлив: ", (existsCoffee || existsTea) && (existsCookie || Existscone));

Если бы вложенные выражения не были заключены в круглые скобки, выражения были бы
вычислены в соответствии с правилами приоритета операторов D (которые были унаследованы
из языка Си). Поскольку в этих правилах && имеет более высокий приоритет, чем ||,
запись выражения без круглых скобок не будет оценена должным образом:

.. code-block:: d

    writeln("Я счастлив: ",existsCoffee || existsTea && existsCookie || existsScone);

Оператор && был бы вычислен первым, и все выражение было бы
семантическим эквивалентом следующего выражения:

.. code-block:: d

    writeln("Я счастлив: ",existsCoffee || (existsTea && existsCookie) || Existscone);

Это имеет совершенно другое значение: "если есть кофе, или чай, и печенье, или булочка;тогда я счастлив".
Таблица приоритета операторов будет представлена позже в книге (ссылка на страницу).

Чтение входных данных bool
--------------------------

Все приведенные выше значения bool автоматически выводятся как "false" или "true". То
же самое в обратном направлении: readf() автоматически преобразует строки "false" и "true" в значения bool false и true соответственно.
Он также принимает любую комбинацию строчных и прописных букв. Например, "False" и "ЛОЖНЫЙ" преобразуются в false, а "True" и "ИСТИНА" преобразуются в true.
Обратите внимание, что это имеет место только при чтении в переменные bool. В противном случае значение
входные данные считывались бы как есть без преобразования при чтении в строковую
переменную. (Как мы увидим позже в главе "строки" (стр. 75),
при чтении строк необходимо использовать readln().)

Упражнения
-----------

Выше мы видели, что операторы < и > используются для определения того, является ли
значение меньше или больше другого значения; но нет оператора, который
отвечал бы на вопрос "находится между?" чтобы определить, находится ли значение между
двумя другими значениями.
Давайте предположим, что программист написал следующий код для
определите, находится ли значение в диапазоне от 10 до 20. Обратите внимание, что программа
не может быть скомпилирована так, как написано:

.. code-block:: d

    import std.stdio;

    void main()
    {
        int value = 15;
        writeln("Находится между: ", 10 < value < 20); // ← ошибка компиляции
    }


Попробуйте использовать круглые скобки вокруг всего выражения:

.. code-block:: d

    writeln("Находится между: ",(10 < value < 20)); // ← ошибка компиляции

Обратите внимание, что он по-прежнему не может быть скомпилирован.
